package com.ruixi.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 * @author lrzg
 * @date 2021-10-25 09:32
 * @Description 访问日志拦截(用于记录web请求 / 响应日志)
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    /**
     * 定义切入点controller
     */
    @Pointcut("execution( public * com.ruixi.controller.*.*(..))")
    public void Log() {

    }

    /**
     * 前置通知，请求方法之前拦截
     *
     * @param joinPoint
     */
    @Before("Log()")
    public void doBefore(JoinPoint joinPoint) {
        //接收到请求记录请求内容
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        //记录下请求内容
        log.info("URL:" + request.getRequestURI());
        log.info("HTTP_METHOD:" + request.getMethod());
        log.info("IP:" + request.getRemoteAddr());

        if ("POST".equals(request.getMethod())) {
            int c = 0;
            ObjectMapper mapper = new ObjectMapper();
            Object[] args = joinPoint.getArgs();
            for (Object arg : args) {
                try {
                    log.info("请求参数[{}]:{}", c, mapper.writeValueAsString(arg));
                } catch (JsonProcessingException ex) {
                    log.error("请求参数转换异常", ex);
                }
                c++;
            }
        } else if ("GET".equals(request.getMethod())) {
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String name = parameterNames.nextElement();
                log.info("{}:{}", name, request.getParameter(name));
            }
        }
    }

    /**
     * 环绕增强，相当于MethodInterceptor
     *
     * @param joinPoint
     * @return
     */
    @Around("Log()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        long beginTime = System.currentTimeMillis();
        result = joinPoint.proceed();
        long time = System.currentTimeMillis() - beginTime;
        log.info("请求耗时:" + time);
        return result;
    }

    @AfterReturning(returning = "ret", pointcut = "Log()")
    public void doAfterReturning(Object ret) {
        //处理完请求，返回内容
//        log.info("RESPONSE:" + ret);
    }
}
